package org.jsets.fastboot.security.authz;

import java.util.Iterator;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import org.jsets.fastboot.util.CollectionUtils;
import org.jsets.fastboot.util.StringUtils;
import org.jsets.fastboot.security.SecurityContext;
import org.jsets.fastboot.security.SecurityUtils;
import org.jsets.fastboot.security.authc.AuthInfo;
import org.jsets.fastboot.security.token.TokenStub;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AuthorizerImpl implements IAuthorizer {

	@Override
	public boolean isAuthorised(String subsystem, String httpMethod, String servletPath) {
		String target = subsystem +" " + httpMethod + " " + servletPath;
		
		AuthzRule authzRule = SecurityUtils.getAuthzRuleManager().getAuthzRule(subsystem, httpMethod, servletPath);
		if (null == authzRule) {
			log.info("地址[{}]无需鉴权", target);
			return true;
		}
		
		if (CollectionUtils.notEmpty(authzRule.getRoles()) && this.hasAnyRole(target, authzRule.getRoles())) {
			return true;
		}

		if (CollectionUtils.notEmpty(authzRule.getPermissions()) && this.isPermittedAny(target, authzRule.getPermissions())) {
			return true;
		}

		return false;
	}

	@Override
	public boolean hasRole(String roleIdentifier) {
		TokenStub stub = this.getCurrentTokenStub();
		if (Objects.isNull(stub)) {
			return false;
		}

		Set<String> roles = SecurityUtils.getUserInfoProvider().loadRoles(stub.getType(), stub.getUsername());
		if (CollectionUtils.isEmpty(roles)) {
			return false;
		}

		boolean allowed = roles.contains(roleIdentifier);
		SecurityUtils.getListenerManager().onRoleAssert(stub.getUsername(), "", StringUtils.join(roles), roleIdentifier, allowed);
		return allowed;
	}

	@Override
	public boolean hasAnyRole(String target, Set<String> roleIdentifiers) {
		TokenStub stub = this.getCurrentTokenStub();
		if (Objects.isNull(stub)) {
			return false;
		}

		Set<String> roles = SecurityUtils.getUserInfoProvider().loadRoles(stub.getType(), stub.getUsername());
		if (CollectionUtils.isEmpty(roles)) {
			log.info("用户[{}]角色列表为空", stub.getUsername());
			return false;
		}

		for (Iterator<String> iterator = roleIdentifiers.iterator(); iterator.hasNext();) {
			String roleIdentifier = iterator.next();
			if (roles.contains(roleIdentifier)) {
				log.info("访问目标[{}]，需要角色[{}]，用户[{}]持有角色[{}]，授权成功", target, StringUtils.join(roleIdentifiers), stub.getUsername(), StringUtils.join(roles));
				SecurityUtils.getListenerManager().onRoleAssert(stub.getUsername(), target, StringUtils.join(roles), roleIdentifier, true);
				return true;
			}
		}

		log.info("访问目标[{}]，需要角色[{}]，用户[{}]持有角色[{}]，授权失败", target, StringUtils.join(roleIdentifiers), stub.getUsername(), StringUtils.join(roles));
		SecurityUtils.getListenerManager().onRoleAssert(stub.getUsername(), target, StringUtils.join(roles),StringUtils.join(roleIdentifiers), false);
		return false;
	}

	@Override
	public boolean hasAllRoles(Set<String> roleIdentifiers) {
		TokenStub stub = this.getCurrentTokenStub();
		if (Objects.isNull(stub)) {
			return false;
		}

		Set<String> roles = SecurityUtils.getUserInfoProvider().loadRoles(stub.getType(), stub.getUsername());
		if (CollectionUtils.isEmpty(roles)) {
			return false;
		}

		for (Iterator<String> iterator = roleIdentifiers.iterator(); iterator.hasNext();) {
			String roleIdentifier = iterator.next();
			if (!roles.contains(roleIdentifier)) {
				SecurityUtils.getListenerManager().onRoleAssert(stub.getUsername(), "", StringUtils.join(roles), StringUtils.join(roleIdentifiers), false);
				return false;
			}
		}

		SecurityUtils.getListenerManager().onRoleAssert(stub.getUsername(), "", StringUtils.join(roles), StringUtils.join(roleIdentifiers), true);
		return true;
	}

	@Override
	public boolean isPermitted(String permission) {
		TokenStub stub = this.getCurrentTokenStub();
		if (Objects.isNull(stub)) {
			return false;
		}

		Set<String> permissions = SecurityUtils.getUserInfoProvider().loadPermissions(stub.getType(), stub.getUsername());
		if (CollectionUtils.isEmpty(permissions)) {
			return false;
		}

		boolean allowed = permissions.contains(permission);
		SecurityUtils.getListenerManager().onPermissionAssert(stub.getUsername(), "",  StringUtils.join(permissions), permission, allowed);
		return allowed;
	}

	@Override
	public boolean isPermittedAny(String target, Set<String> permissionIdentifiers) {
		TokenStub stub = this.getCurrentTokenStub();
		if (Objects.isNull(stub)) {
			return false;
		}

		Set<String> permissions = SecurityUtils.getUserInfoProvider().loadPermissions(stub.getType(), stub.getUsername());
		if (CollectionUtils.isEmpty(permissions)) {
			return false;
		}

		for (Iterator<String> iterator = permissionIdentifiers.iterator(); iterator.hasNext();) {
			String permissionIdentifier = iterator.next();
			if (permissions.contains(permissionIdentifier)) {
				log.info("访问目标[{}]，需要权限[{}]，用户[{}]持有权限[{}]，授权成功", target, StringUtils.join(permissionIdentifiers), stub.getUsername(), StringUtils.join(permissions));
				SecurityUtils.getListenerManager().onPermissionAssert(stub.getUsername(), target, StringUtils.join(permissions), StringUtils.join(permissionIdentifiers), true);
				return true;
			}
		}

		log.info("访问目标[{}]，需要权限[{}]，用户[{}]持有权限[{}]，授权失败", target, StringUtils.join(permissionIdentifiers), stub.getUsername(), StringUtils.join(permissions));
		SecurityUtils.getListenerManager().onPermissionAssert(stub.getUsername(), target, StringUtils.join(permissions), StringUtils.join(permissionIdentifiers), false);
		return false;
	}

	@Override
	public boolean isPermittedAll(Set<String> permissionIdentifiers) {
		TokenStub stub = this.getCurrentTokenStub();
		if (Objects.isNull(stub)) {
			return false;
		}

		Set<String> permissions = SecurityUtils.getUserInfoProvider().loadPermissions(stub.getType(), stub.getUsername());
		if (CollectionUtils.isEmpty(permissions)) {
			return false;
		}

		for (Iterator<String> iterator = permissionIdentifiers.iterator(); iterator.hasNext();) {
			String permission = iterator.next();
			if (!permissions.contains(permission)) {
				SecurityUtils.getListenerManager().onPermissionAssert(stub.getUsername(), "", StringUtils.join(permissions), StringUtils.join(permissionIdentifiers), false);
				return false;
			}
		}

		SecurityUtils.getListenerManager().onPermissionAssert(stub.getUsername(), "", StringUtils.join(permissions), StringUtils.join(permissionIdentifiers), true);
		return true;
	}

	/**
	 * 获取当前上下文中的Session
	 * 
	 * @return Session
	 */
	private TokenStub getCurrentTokenStub() {
		AuthInfo authcInfo = SecurityContext.get();
		if (Objects.isNull(authcInfo)) {
			return null;
		}

		Optional<TokenStub> opt = SecurityUtils.getTokenManager().getTokenStub(authcInfo.getAccessTokenId());
		if (!opt.isPresent()) {
			return null;
		}
		return opt.get();
	}

}